package com.my.utils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import com.my.annotation.NotNull;

/**
 * @author Maple.Chen
 * @date 2020年9月29日
 * @description <p>反射</p>
 * 即在程序运行状态，能够动态通过反射得到一个任意对象并获得它的成员变量及方法
 */

/**
 * 针对自定义注解的粗浅运用
 */

public class Reflect {
	/*
	 * 获取反射对象的方法
	 * 1.Class clazz = (new Person()).getClass();
	 * 2.Class clazz = Person.class;
	 * 3.Class clazz = Class.forName("com.xxx.pojo.Person");
	 * 
	 * Field[] field = object.getClass().getDeclaredFields();
	 * Method[] method = object.getClass().getDeclaredMethods();
	 * Constructor[] constructor = object.getClass().getDeclaredConstructors();
	 */
	
	/**
	 * 获取对象类的所有成员变量并打印它们的值
	 * @throws SecurityException 
	 * @throws NoSuchMethodException 
	 * @throws InvocationTargetException 
	 * @throws IllegalArgumentException 
	 * @throws IllegalAccessException 
	 */
	public static void printVariablesValue(Object object) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException{
		Field[] field = object.getClass().getDeclaredFields();
		Object value;
		for(int j=0 ; j<field.length ; j++) {     //遍历所有属性
			String name = field[j].getName();    //获取属性的名字
			name = name.substring(0,1).toUpperCase()+name.substring(1); //将属性的首字符大写，方便构造get，set方法
			String type = field[j].getGenericType().toString();    //获取属性的类型
			value = object.getClass().getMethod("get"+name).invoke(object);  // 前提是实体类必须对每个成员变量写一个Getter方法
			switch ( type ) {
				case "class java.lang.String" : {
					System.out.println( name + ".value=" + (String) value );
					break;
				}
				case "class java.lang.Integer" : {
					System.out.println( name + ".value=" + (Integer) value );
					break;
				}
				case "class java.lang.Short" : {
					System.out.println( name + ".value=" + (Short) value );
					break;
				}
				case "class java.lang.Double" : {
					System.out.println( name + ".value=" + (Double) value );
					break;
				}
				case "class java.lang.Boolean" : {
					System.out.println( name + ".value=" + (Boolean) value );
					break;
				}
				case "class java.util.Date" : {
					System.out.println( name + ".value=" + (Date) value );
					break;
				}
				default : break;
			}
		}
	}
	
	/**
	 * 针对自己设定的@NotNull实现属性校验
	 * # 
	 * @throws IllegalAccessException 
	 * @throws IllegalArgumentException 
	 * # 
	 * @throws SecurityException 
	 * @throws NoSuchMethodException
	 * # 
	 * @throws InvocationTargetException 
	 * !!! 使用该方法前前请确保JavaBean对象支持get和set方法
	 * !!! (Make sure JavaBean objects support get and set methods before using this method)
	 */
	public static Map<String, String> MyNotNullRulVvalidate(Object object) throws IllegalArgumentException, IllegalAccessException, NoSuchMethodException, SecurityException, InvocationTargetException{
		// 声明一个待输出的“校验结果集”
		Map<String, String> resultMap = new HashMap<>();
		// 获取所有属性.
	    Field[] declaredFields = object.getClass().getDeclaredFields();
	    // 遍历所有属性.
	    for (Field field : declaredFields) {
	    	/**
	    	 * 针对某个加了自定义注解的变量进行判断
	    	 */
	    	if ( field.isAnnotationPresent(NotNull.class) ){
	    		// 关闭访问安全检查，防止抛出IllegalAccessException异常
	    		field.setAccessible(true);
	    		// 获取对象类型
	    		Class<?> fieldType = field.getType();
	    		// 获取属性的名字
	    		String name = field.getName();
				name = name.substring(0,1).toUpperCase()+name.substring(1); //将属性的首字符大写，方便构造get，set方法
	    		// 成员变量的getter的方法
				Method method = object.getClass().getMethod("get" + name);
				/**
	    		 * 1.判断对象类型,仅支持以下类型
	    		 */
	    		if ( fieldType.isAssignableFrom(String.class) || 
	    				fieldType.isAssignableFrom(Boolean.class) ||
	    				fieldType.isAssignableFrom(Integer.class)
	    				) {
	    			// 获取该成员变量的NotNull对象
	    			NotNull notNull = field.getAnnotation(NotNull.class);
	    			// 如果needBao值为true,则略过非空校验
	    			if ( notNull.needBao() )
	    				continue;
			        // 否则：调用getter方法获取属性值，进行非空校验
	    			Object value = method.invoke(object);
	    			if ( value == null ) {
//	  		          	throw new IllegalArgumentException(notNull.fieldName() + " 不能为空");
	    				resultMap.put(notNull.fieldName(), name + "属性不能为空" );
	    			}else if ( value != null ) {
	    				/**
	    				 * 此处可扩展正则校验
	    				 */
//	    				if ( !(value instanceof Integer) ){
//	    					System.out.println(notNull.fieldName()+ "  " + name + "属性不为数字,value = " + value);
//	    				}
	    			}
			    }
	    		// 可自定义扩展支持对<其他类型>的成员变量进行判断
	    	}
	    }
		return resultMap;
	}
	
}
